#pragma once
#include "PackedStringAllocator.h"
// 模板参数
// CAGETORY	: 用于区分是哪一类,避免将不同作用的字符串混合放在一个分配器中
// CAPCITY  : 用于指明该字符串的最大长度特征等或者平均长度特征等
template<int CAGETORY, int CAPCITY, typename Allocator = PackedStringAllocator>
class  PackedString{
public:
	typedef PackedString<CAGETORY, CAPCITY> ThisType;
	typedef char Element;
	template<class T>
	static void SwapValue(T& v1, T& v2){ T temp = v1; v1 = v2; v2 = temp; }
	Element*			m_string;	// 字符串内存,默认为m_null
public://constructors
	PackedString() :m_string(Allocator::GetNullString()){}
	PackedString(const Element* str) : m_string(Allocator::GetNullString()){
		if (str && *str != '\0')
			asign(str, str ? strlen(str) : 0);
	}
	PackedString(const Element* str, int len) : m_string(Allocator::GetNullString())
	{
		if (str && *str != '\0' && len>0)
			asign(str, len);
	}
	PackedString(const ThisType& bs) : m_string(Allocator::GetNullString())
	{
		if (!bs.empty())
			asign(bs.c_str(), bs.size());
	}
	~PackedString(){ reset(); }
	int Category()const{ return CAGETORY; }
	ThisType& operator=(const Element* str){ return asign(str, str ? strlen(str) : 0); }
	ThisType& operator=(const ThisType& bs){ return asign(bs.c_str(), bs.size()); }
	ThisType& asign(const Element* str, int len)
	{
		if (str != c_str())
		{
			expand(str, len);
		}
		return *this;
	}
	ThisType& append(const Element* str, int len)
	{
		if (str && len > 0)
		{
			expand(c_str(), size(), str, len);
		}
		return *this;
	}
	void reset()
	{
		if (m_string && m_string != Allocator::GetNullString())
			Allocator::Free(m_string);
		m_string = Allocator::GetNullString();
	}
protected:
	void expand(const Element* str, int size, const Element* str2 = 0, int size2 = 0)
	{
		int total = size + size2;
		if (total <= 0)
		{
			m_string = Allocator::GetNullString();
			return;
		}

		Element* buf = (Element*)Allocator::Alloc((total + 1)*sizeof(Element));
		if (buf == NULL)
			return;
		buf[0] = '\0';
		if (str && size > 0)
			memcpy(buf, str, size);
		if (str2 && size2 > 0)
			memcpy(buf + size, str2, size2);
		buf[total] = '\0';
		reset();
		m_string = buf;
	}
	void swap(ThisType& bs){SwapValue(m_string, bs.m_string);}
public://operators,const
	int compare(const Element* str, int len)const
	{
		if (!str || len <= 0)
			return empty() ? 0 : 1;	// 有值为大
		if (empty())
			return (!str || len <= 0) ? 0 : -1;
		return strcmp(c_str(), str);
	}
	bool operator==(const ThisType& bs)const{ return compare(bs.c_str(), bs.size()) == 0; }
	bool operator==(const Element* str)const{ return compare(str, str ? strlen(str) : 0) == 0; }
	bool operator!=(const ThisType& bs)const{ return compare(bs.c_str(), bs.size()) != 0; }
	bool operator!=(const Element* str)const{ return compare(str, str ? strlen(str) : 0) != 0; }
public://accessors,const
	const Element* c_str()const{return m_string;}
	operator const Element*()const{ return m_string; }
	int size()const{ return strlen(m_string); }
	int memory()const{ return sizeof(*this) + size() + 1; }
	bool empty()const{ return *m_string=='\0'; }
	Element at(int i)const{return (i < 0 || m_string == Allocator::GetNullString()) ? Element(0) : m_string[i];}
	Element operator[](int i)const{ return at(i); }
};

